home *** CD-ROM | disk | FTP | other *** search
- {******************************************************************}
- { }
- { Mancala }
- { Turbo Pascal for Windows }
- { Copyright (c) 1991 by Swan Software. All rights reserved. }
- { }
- {******************************************************************}
-
- { usearch.pas -- Alpha/Beta game search engine for Mancala }
-
- unit USearch;
-
- interface
-
- uses WinTypes, WinProcs, UGlobals, UEval, UMove;
-
- procedure Search(var Position: Boardrec; Level: Integer;
- var FinalScore: Integer; MoveList: ListRec; Alpha: Integer;
- Beta: Integer);
-
-
- implementation
-
-
- {- Perform minimax search with alpha-beta cutoffs. Finds best move
- that limits opponent's maximum potential gain. When finished, global
- bestmove equals the selected move. Requires variable MaxPly set to
- the maximum search depth. Start search with Level = 1. Variable
- FinalScore does not have to be initialized. MoveList.FirstIndex
- should address the list of legal moves (returned by MoveGen) for this
- level. Initialize Alpha to -maxInt and Beta to +Maxint when calling
- search the first time. If there are no moves for this position
- (MoveList.Count = 0), the FinalScore is the board evaluation. When this
- procedure ends, the global MoveStack index (MoveIndex) is reset to
- MoveLst.FirstIndex - 1, removing the MoveList from the stack and
- recovering the space the moves occupy. After this procedure ends,
- then, MoveList is no longer valid. Set global LowLevel to the level
- used to start the search. If Level = 0, then the computer will search
- for human's best move. }
-
- procedure Search(var Position: Boardrec; Level: Integer;
- var FinalScore: Integer; MoveList: ListRec; Alpha: Integer;
- Beta: Integer);
- var
- M: Integer; { Movestack index to MoveRecs }
- NewList: ListRec; { New move lists to search }
- MinMaxIndex: StackRange; { Index to MinMax move }
- MaxScore: Integer; { Max score on odd levels }
- MinScore: Integer; { Min score on even levels }
- OldCursor: HCursor; { Saved cursor handle during search }
- begin
-
- OldCursor := SetCursor(LoadCursor(0, idc_Wait));
-
- with MoveList do { Investigate moves on this list }
-
- {- If the MoveList is empty (Count = 0), then end the search now,
- leaving FinalScore unchanged. }
-
- if Count > 0 then
- begin
-
- MinMaxIndex := FirstIndex; { Initialize final move index
- to the first move on the
- sorted move list. }
-
- {- Check the level. If it is less than the maximum ply number
- (MaxPly), then continue the search by calling MoveGen with the board
- position reached after making each move on the move list. If the
- search level equals MaxPly, then the search has reached the deepest
- level of the tree and MinMaxIndex equals the MoveStack index of the
- chosen move on this level. }
-
- if Level < MaxPly then
- begin { Continue searching for the best move }
- M := FirstIndex; { Initialize move index }
- MaxScore := -maxInt; { < any possible score }
- MinScore := +maxInt; { > any possible score }
- while M <= LastIndex do with MoveStack[M] do
- begin
- with BoardStack[BoardIndex] do
- if GoAgain then
- begin
- MoveGen(BoardStack[BoardIndex], Level, NewList);
- Search(BoardStack[BoardIndex], Level, Score,
- NewList, Alpha, Beta);
- end else
- begin
- MoveGen(BoardStack[BoardIndex], Level + 1, NewList);
- Search(BoardStack[BoardIndex], Level + 1, Score,
- Newlist, Alpha, Beta);
- end;
-
- {- Keep track of greatest (Alpha) or lowest (Beta) score on this level
- for passing to further searches. The result, Alpha or Beta, also
- becomes the result of the minimax algorithm--the value passed up
- through the tree as the final score for this level. Odd levels affect
- alpha values, but use beta values to produce cutoffs. Even levels
- affect beta values but use alpha values for cutoffs. In this way, the
- alpha beta values double as variables holding the best or worst
- scores, while indicating from lower tree levels when there is no
- reason to continue searching. }
-
- if Odd(Level) then
- begin
- if Score > Alpha then { Adjust alpha value }
- Alpha := Score;
- if Score > MaxScore then { Record highest score }
- begin
- MaxScore := Score; { Highest score so far }
- MinMaxIndex := M; { Movestack index }
- end;
- if Score >= Beta then
- M := LastIndex; { Beta cutoff }
- end else
- begin
- if Score < Beta then { Adjust beta value }
- Beta := Score;
- if Score < MinScore then { Record lowest score }
- begin
- MinScore := Score; { Lowest score so far }
- MinMaxIndex := M; { MoveStack index }
- end;
- if Score <= Alpha then
- M := LastIndex; { Alpha cutoff }
- end;
- Inc(M); { Advance move index }
- end;
- end;
-
- with MoveStack[MinMaxIndex] do { Select minimax move }
- begin
- FinalScore := Score; { Pass up final score }
- BestMove := Move; { Assign best move }
- end;
-
- {- Setting the global MoveIndex to FirstIndex - 1 moves the index
- back to its position before the move list for this search level was
- generated. The MoveIndex is the stack pointer to the MoveStack and
- BoardStack arrays. This action, then, reclaims space on the stack for
- future move lists and board copies. }
-
- MoveIndex := FirstIndex - 1; { Dispose move list and
- gameboard copies. }
- end;
-
- SetCursor(OldCursor);
-
- end;
-
-
- end.
-
-
- { ----------------------------------------------------------------
- Copyright (c) 1991 by Swan Software. All rights reserved.
- Revision 1.00 Date: 8/21/1991
- ---------------------------------------------------------------- }
-